﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using DataLayer;
using DataLayer.Model.Classes;
using DataLayer.Model.Objects;
using Overview.Components;
using Action = DataLayer.Model.Objects.Action;
using BuisnessLayer;

namespace Overview
{
    /// <summary>
    /// Interaction logic for MacroEditorControl.xaml
    /// </summary>
    public partial class MacroEditorControl : Window
    {
        private readonly Character _character;
        private Macro _macro;
        private int _pointedAction = -1;
        public Point startPoint { get; set; }

        public MacroEditorControl(Character pCharacter, ref Macro pMacro)
        {
            _character = pCharacter;
            _macro = pMacro;
            InitializeComponent();
            LoadAvailableActions();
            LoadAvailableSkills(); 
            LoadMacroActions();
            LblMacroName.Content = pMacro.Name;
        }

        private void LoadAvailableActions()
        {
            ExpnActionsGrid.RowDefinitions.Add(new RowDefinition());
            var columnIndex = 0;
            var rowIndex = 0;
            foreach (var command in Singleton.ReadAllActions())
            {
                var action = new ActionControl(command);
                Grid.SetColumn(action, columnIndex++);
                Grid.SetRow(action, rowIndex);
                if (columnIndex >3)
                {
                    columnIndex = 0;
                    rowIndex++;
                    ExpnActionsGrid.RowDefinitions.Add(new RowDefinition());
                }
                ExpnActionsGrid.Children.Add(action);
            }
        }

        private void LoadAvailableSkills()
        {
            ExpnSkillsGrid.RowDefinitions.Add(new RowDefinition());
            var columnIndex = 0;
            var rowIndex = 0;
            foreach (var skill in _character.Skills)
            {
                if (skill.SkillType != OccupationsOccupationSkillType.Active)
                    continue;
                var action = new ActionControl(skill);
                Grid.SetColumn(action, columnIndex++);
                Grid.SetRow(action, rowIndex);
                if (columnIndex > 3)
                {
                    columnIndex = 0;
                    rowIndex++;
                    ExpnSkillsGrid.RowDefinitions.Add(new RowDefinition());
                }
                ExpnSkillsGrid.Children.Add(action);
            }
        }

        private void LoadMacroActions()
        {
            if ((_macro != null && _macro.Actions!=null && _macro.Actions.Count != 0))
                foreach (var action in _macro.Actions)
                    AddItemToMacroActions(action, -1);

        }

        private void AddItemToMacroActions(Action pAction, int index) {
            var actionItem = new ActionInListComponent(pAction);
            actionItem.DragEnter += new DragEventHandler(Grid_DragEnter); 
            actionItem.Drop += new DragEventHandler(GiveMyPositionIndex);
            if (index<0)
                SpnlMacroActions.Children.Add(actionItem);
            else
            {
                 SpnlMacroActions.Children.Insert(index,actionItem);
            }
        }

        public void SaveMacro()
        {
            foreach (var element in SpnlMacroActions.Children)
                if (element.GetType()== typeof(ActionInListComponent))
                    _macro.Add(((ActionInListComponent)element).Action);

            this.Close();
        }


        private void ExpnActionsGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            startPoint = e.GetPosition(null);
        }

        private void ExpnActionsGrid_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            // Get the current mouse position
            Point mousePos = e.GetPosition(null);
            Vector diff = startPoint - mousePos;

            if (e.LeftButton == MouseButtonState.Pressed &&
                Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
                Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
            {
                // Get the dragged ListViewItem
                var actionItem = sender as Expander;
                var expanderViewItem =
                    FindAnchestor<ActionControl>((DependencyObject)e.OriginalSource);

                // Find the data behind the ListViewItem
                if (expanderViewItem == null)
                    return;
                var action = expanderViewItem.Action;

                // Initialize the drag & drop operation
                var dragData = new DataObject("myFormat", action);
                DragDrop.DoDragDrop(expanderViewItem, dragData, DragDropEffects.Move);
            } 

        }
        // Helper to search up the VisualTree
        private static T FindAnchestor<T>(DependencyObject current)
            where T : DependencyObject
        {
            try
            {
                do
                {
                    if (current is T)
                        return (T)current;
                    current = VisualTreeHelper.GetParent(current);
                }
                while (current != null);
            }
            catch (InvalidOperationException)
            {
            }
            return null;
        }

        private void Grid_DragEnter(object sender, DragEventArgs e)
        { 
            if (!e.Data.GetDataPresent("myFormat") ||sender == e.Source)
                e.Effects = DragDropEffects.None;
        }

        private void SpnlMacroActionsGrid_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent("myFormat"))
            {
                 var action = e.Data.GetData("myFormat") as DataLayer.Model.Objects.Action;
                 if (action.Name.Contains("[target]"))
                     action.Name.Replace("[target]", UserInteract.AskStringData(new AskerMessage{
                        ConfirmContent = "Confirm",
                        Message = "Specify action target.",
                        Title ="Target select",
                        DiscardContent = "Cancel"
                    }));
                 AddItemToMacroActions(action, _pointedAction);
                 _pointedAction = -1;
            }
        }

        private void GiveMyPositionIndex(object sender, DragEventArgs e){
            _pointedAction = FindItemInStack(sender);
        }
        private int FindItemInStack(object sender)
        {
            int index = 0;
            foreach (var element in SpnlMacroActions.Children)
            {
                if (element.Equals(sender))
                    return index;
                index++;
            }
            return -1;
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
            this.Close();
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
            SaveMacro();
        }

        private void LblMacroName_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var newName = UserInteract.AskStringData(new AskerMessage
            {
                ConfirmContent = "Change",
                Message = "Enter macro name.",
                Title = "Macro name",
                DiscardContent = "Cancel"
            });
            if (newName == null)
                return;

            _macro.Name = newName;
            LblMacroName.Content = _macro.Name;
        }
    }
}
